// File: kmp_BaseDefs.h
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// http://go.microsoft.com/fwlink/?LinkId=link-me
//--------------------------------------------------------------------------------------

#ifdef _MSC_VER
#pragma once
#endif

#ifndef KMP_BASEDEFS_H
#define KMP_BASEDEFS_H

#include "kmp_Preprocessor.h"

/**
Calling convention  // currently defined for windows only, needs searching for other platforms
*/
#if defined(KMP_VC)
# ifndef KMP_CALLCONV
#  if defined(KMP_VECTORCALL)
#	if defined(KMP_VC12)
#		define KMP_CALLCONV __vectorcall
#	else
#		define KMP_CALLCONV __fastcall
#	endif
#  else 
#	  define KMP_CALLCONV __fastcall
#  endif
#	define KMP_CDECL __cdecl
#	define KMP_STDCALL __stdcall
#	define KMP_FASTCALL __fastcall
# if defined(KMP_VECTORCALL)
#	if defined(KMP_VC12)
#		define KMP_VECCALL __vectorcall
#	else
#		define KMP_CALLCONV __fastcall
#	endif
#  endif
# endif
#else
#define KMP_CALLCONV
#define KMP_CDECL
#define KMP_STDCALL
#define KMP_FASTCALL
#define KMP_VECCALL
#endif

/**
Inline macro
*/
#if defined(KMP_WINDOWS) || defined(KMP_ARM)  || defined(KMP_XBOXONE)|| defined(KMP_XBOX360) || defined(KMP_PC_APP)
#	define KMP_INLIN inline
//#	pragma inline_depth( 255 )
# if defined(KMP_VC)
#	ifndef KMP_INLINE
#	  ifndef _DEBUG
#		define KMP_INLINE __forceinline
// inline on in release build for static inline
#		define __KMP_INLINE static __forceinline
// inline on in release build for inline only
#		define _KMP_INLINE __forceinline
#		define _KMP_INLINE __forceinline
#	  else 
#		define KMP_INLINE __inline
// inline of in debug build for static inline
#		define __KMP_INLINE static	
// inline of in debug build for inline only
#		define _KMP_INLINE

#	  endif
#	endif
#		define KMP_FINLINE __forceinline
# else
#	ifndef KMP_INLINE
#	  ifndef _DEBUG
#		define KMP_INLINE __inline
#		define __KMP_INLINE static __inline
#		define _KMP_INLINE __inline
#	  else 
#		define KMP_INLINE __inline
#		define __KMP_INLINE static
#		define _KMP_INLINE
#	  endif
#		define KMP_FINLINE __forceinline
#	endif
# endif
#else
#	define KMP_INLINE inline
#	define __KMP_INLINE static inline
#	define KMP_FINLINE inline
#endif


/**
Noinline macro
*/
#if defined(KMP_WINDOWS) || defined(KMP_ARM) || defined(KMP_XBOXONE) || defined(KMP_XBOX360) || defined(KMP_PC_APP)
# if defined(KMP_VC)
#	define KMP_NOINLINE __declspec(noinline)
# else
#	define KMP_NOINLINE
# endif
#else
#	define KMP_NOINLINE 
#endif

/*! restrict macro */
#if defined(KMP_CLANG) || (defined(KMP_VC) && (_MSC_VER >= 1400))
#	define KMP_RESTRICT __restrict
#else
#	define KMP_RESTRICT
#endif

/*

/ * noalias macro * /
#if defined(KMP_WINDOWS) || defined(KMP_ARM) || defined(KMP_XBOXONE) || defined(KMP_XBOX360) || defined(KMP_PC_APP)
#define KMP_NOALIAS __declspec(noalias)
#else
#define KMP_NOALIAS
#endif
*/

/* alignof macro */
#if defined(KMP_VC)
#define KMP_ALIGN_OF(X) __alignof(X)
#else
#define KMP_ALIGN_OF
#endif

#if defined (KMP_VC)
#	if (_MSC_VER >= 1700)
#		define KMP_OVERRIDE override
#		define KMP_FINAL	final
#		define KMP_FINAL_OVERRIDE final override
#	elif (_MSC_VER >= 1600)
#		define KMP_OVERRIDE override
#		define KMP_FINAL	sealed
#		define KMP_FINAL_OVERRIDE sealed override
#endif
#endif

#if defined(KMP_PC_APP) || defined(KMP_PHONE_APP) || defined(KMP_DESKTOP_APP)
#define KMP_VIRTUAL
#define KMP_VIRTUAL_SPECIFI
#else
#define KMP_VIRTUAL virtual
#define KMP_VIRTUAL_SPECIFI = 0
#endif

/**
Alignment macros

KMP_ALIGN_PREFIX and KMP_ALIGN_SUFFIX can be used for type alignment instead of aligning individual variables as follows:
KMP_ALIGN_PREFIX(16)
struct A {
...
} KMP_ALIGN_SUFFIX(16);
This declaration style is parsed correctly by Visual Assist.
*/
/*

#if defined(KMP_VC) && !defined(KMP_NO_ALIGN)

#		define KMP_ALIGNMENTDECL(alignment, decl) __declspec(align(alignment)) decl
#		define KMP_ALIGN_PREFIX(alignment) __declspec(align(alignment))
#		define KMP_ALIGN_SUFFIX(alignment)

#		define KMP_ALIGNDECL(decl, alignment) __declspec(align(alignment)) decl
#		define KMP_ALIGN4DECL(decl) __declspec(align(4)) decl
#		define KMP_ALIGN8DECL(decl) __declspec(align(8)) decl
#		define KMP_ALIGN16DECL(decl) __declspec(align(16)) decl
#		define KMP_ALIGN32DECL(decl) __declspec(align(32)) decl
#		define KMP_ALIGN64DECL(decl) __declspec(align(64)) decl
#		define KMP_ALIGN128DECL(decl) __declspec(align(128)) decl
#		define KMP_ALIGN256DECL(decl) __declspec(align(256)) decl


#	define KMP_ALIGN4 __declspec(align(4))
#	define KMP_ALIGN8 __declspec(align(8))
#	define KMP_ALIGN16 __declspec(align(16))
#	define KMP_ALIGN32 __declspec(align(32))
#	define KMP_ALIGN64 __declspec(align(64))
#	define KMP_ALIGN128 __declspec(align(128))
#	define KMP_ALIGN256 __declspec(align(256))
#	define KMP_ALIGN512 __declspec(align(512))

#		define KMP_CLASSALIGNDECL(decl, alignment) KMP_ALIGNDECL(decl, alignment)
#		define KMP_CLASSALIGN4DECL(decl) KMP_ALIGN4DECL(decl)
#		define KMP_CLASSALIGN8DECL(decl) KMP_ALIGN8DECL(decl)
#		define KMP_CLASSALIGN16DECL(decl) KMP_ALIGN16DECL(decl)
#		define KMP_CLASSALIGN32DECL(decl) KMP_ALIGN32DECL(decl)
#		define KMP_CLASSALIGN64DECL(decl) KMP_ALIGN64DECL(decl)
#		define KMP_CLASSALIGN128DECL(decl) KMP_ALIGN128DECL(decl)
#		define KMP_CLASSALIGN256DECL(decl) KMP_ALIGN256DECL(decl)

#elif defined(KMP_NO_ALIGN)
#define KMP_ALIGNMENTDECL(alignment, decl)
#define KMP_ALIGN_PREFIX(alignment)
#define KMP_ALIGN_SUFFIX(alignment)

#define KMP_ALIGNDECL(decl, alignment)
#define KMP_ALIGN4DECL(decl)
#define KMP_ALIGN8DECL(decl)
#define KMP_ALIGN16DECL(decl)
#define KMP_ALIGN32DECL(decl)
#define KMP_ALIGN64DECL(decl)
#define KMP_ALIGN128DECL(decl)
#define KMP_ALIGN256DECL(decl)

#define KMP_ALIGN4
#define KMP_ALIGN8
#define KMP_ALIGN16
#define KMP_ALIGN32
#define KMP_ALIGN64
#define KMP_ALIGN128
#define KMP_ALIGN256
#define KMP_ALIGN512

#		define KMP_CLASSALIGNDECL(decl, alignment) KMP_ALIGNDECL(decl, alignment)
#		define KMP_CLASSALIGN4DECL(decl) KMP_ALIGN4DECL(decl)
#		define KMP_CLASSALIGN8DECL(decl) KMP_ALIGN8DECL(decl)
#		define KMP_CLASSALIGN16DECL(decl) KMP_ALIGN16DECL(decl)
#		define KMP_CLASSALIGN32DECL(decl) KMP_ALIGN32DECL(decl)
#		define KMP_CLASSALIGN64DECL(decl) KMP_ALIGN64DECL(decl)
#		define KMP_CLASSALIGN128DECL(decl) KMP_ALIGN128DECL(decl)
#		define KMP_CLASSALIGN256DECL(decl) KMP_ALIGN256DECL(decl)

#else
#define KMP_ALIGNMENTDECL(alignment, decl)
#define KMP_ALIGN_PREFIX(alignment)
#define KMP_ALIGN_SUFFIX(alignment)

#define KMP_ALIGNDECL(decl, alignment)
#define KMP_ALIGN4DECL(decl)
#define KMP_ALIGN8DECL(decl)
#define KMP_ALIGN16DECL(decl)
#define KMP_ALIGN32DECL(decl)
#define KMP_ALIGN64DECL(decl)
#define KMP_ALIGN128DECL(decl)
#define KMP_ALIGN256DECL(decl)

#define KMP_ALIGN4
#define KMP_ALIGN8
#define KMP_ALIGN16
#define KMP_ALIGN32
#define KMP_ALIGN64
#define KMP_ALIGN128
#define KMP_ALIGN256
#define KMP_ALIGN512

#		define KMP_CLASSALIGNDECL(decl, alignment) KMP_ALIGNDECL(decl, alignment)
#		define KMP_CLASSALIGN4DECL(decl) KMP_ALIGN4DECL(decl)
#		define KMP_CLASSALIGN8DECL(decl) KMP_ALIGN8DECL(decl)
#		define KMP_CLASSALIGN16DECL(decl) KMP_ALIGN16DECL(decl)
#		define KMP_CLASSALIGN32DECL(decl) KMP_ALIGN32DECL(decl)
#		define KMP_CLASSALIGN64DECL(decl) KMP_ALIGN64DECL(decl)
#		define KMP_CLASSALIGN128DECL(decl) KMP_ALIGN128DECL(decl)
#		define KMP_CLASSALIGN256DECL(decl) KMP_ALIGN256DECL(decl)

#endif

#		define KMP_VISIBILITY_HIDDEN / *empty* /


#define KMP_F32_ALNUM 16
#define KMP_F64_ALNUM 32
#define KMP_F32_SIZE 4
#define KMP_F64_SIZE 8

#define KMP_ALG_N4 4
#define KMP_ALG_N8 8
#define KMP_ALG_N16 16
#define KMP_ALG_N32 32
#define KMP_ALG_N64 64
#define KMP_ALG_N128 128
#define KMP_ALG_N256 256

#if defined(KMP_WINDOWS) || defined(KMP_XBOXONE)  && !defined(KMP_NO_ALIGN)

#if defined(KMP_X86) && !defined(KMP_X64)

#if !defined(KMP_INTRINSICS_AVX)

// use this in all your needs for alignment
#	define KMP_ALGN KMP_ALG_N16
#	define KMP_ALIGN_F32 KMP_ALIGN16
#	define KMP_ALIGN_F64 KMP_ALIGN16
#	define KMP_ALIGN_REAL KMP_ALIGN16
#	define KMP_ALIGN KMP_ALIGN16
#	define KMP_CLASS_ALIGN KMP_ALIGN16
#	define KMP_PREFIX_ALIGN KMP_ALIGN_PREFIX
#	define KMP_SUFFIX_ALIGN KMP_ALIGN_SUFFIX
#	define KMP_ALIGNMENT_DECL KMP_ALIGNMENTDECL
#	define KMP_ALIGN_DECL KMP_ALIGNDECL

// do not use this at all for portability issues
#	define KMP_ALIGN_F32DECL KMP_ALIGN16DECL
#	define KMP_ALIGN_F64DECL KMP_ALIGN16DECL
#	define KMP_ALIGN_REALDECL KMP_ALIGN16DECL
#	define KMP_ALIGN_NDECL KMP_ALIGN16DECL

#elif defined(KMP_INTRINSICS_AVX) && !defined(KMP_XBOXONE)

// use this in all your needs for alignment
#	define KMP_ALGN KMP_ALG_N32
#	define KMP_ALIGN_F32 KMP_ALIGN32
#	define KMP_ALIGN_F64 KMP_ALIGN32
#	define KMP_ALIGN_REAL KMP_ALIGN32
#	define KMP_ALIGN KMP_ALIGN32
#	define KMP_CLASS_ALIGN KMP_ALIGN32
#	define KMP_PREFIX_ALIGN KMP_ALIGN_PREFIX
#	define KMP_SUFFIX_ALIGN KMP_ALIGN_SUFFIX
#	define KMP_ALIGNMENT_DECL KMP_ALIGNMENTDECL
#	define KMP_ALIGN_DECL KMP_ALIGNDECL

// do not use this at all for portability issues
#	define KMP_ALIGN_F32DECL KMP_ALIGN32DECL
#	define KMP_ALIGN_F64DECL KMP_ALIGN32DECL
#	define KMP_ALIGN_REALDECL KMP_ALIGN32DECL
#	define KMP_ALIGN_NDECL KMP_ALIGN32DECL

#endif

#elif defined(KMP_X64) && !defined(KMP_X86)

#if defined(KMP_INTRINSICS_AVX) && !defined(KMP_XBOXONE)

// use this in all your needs for alignment
#	define KMP_ALGN KMP_ALG_N32
#	define KMP_ALIGN_F32 KMP_ALIGN32
#	define KMP_ALIGN_F64 KMP_ALIGN32
#	define KMP_ALIGN_REAL KMP_ALIGN32
#	define KMP_ALIGN KMP_ALIGN32
#	define KMP_CLASS_ALIGN KMP_ALIGN32
#	define KMP_PREFIX_ALIGN KMP_ALIGN_PREFIX
#	define KMP_SUFFIX_ALIGN KMP_ALIGN_SUFFIX
#	define KMP_ALIGNMENT_DECL KMP_ALIGNMENTDECL
#	define KMP_ALIGN_DECL KMP_ALIGNDECL

// do not use this at all for portability issues
#	define KMP_ALIGN_F32DECL KMP_ALIGN32DECL
#	define KMP_ALIGN_F64DECL KMP_ALIGN32DECL
#	define KMP_ALIGN_REALDECL KMP_ALIGN32DECL
#	define KMP_ALIGN_NDECL KMP_ALIGN32DECL

#else 

// use this in all your needs for alignment
#	define KMP_ALGN KMP_ALG_N16
#	define KMP_ALIGN_F32 KMP_ALIGN16
#	define KMP_ALIGN_F64 KMP_ALIGN16
#	define KMP_ALIGN_REAL KMP_ALIGN16
#	define KMP_ALIGN KMP_ALIGN16
#	define KMP_CLASS_ALIGN KMP_ALIGN16
#	define KMP_PREFIX_ALIGN KMP_ALIGN_PREFIX
#	define KMP_SUFFIX_ALIGN KMP_ALIGN_SUFFIX
#	define KMP_ALIGNMENT_DECL KMP_ALIGNMENTDECL
#	define KMP_ALIGN_DECL KMP_ALIGNDECL

// do not use this at all for portability issues
#	define KMP_ALIGN_F32DECL KMP_ALIGN16DECL
#	define KMP_ALIGN_F64DECL KMP_ALIGN16DECL
#	define KMP_ALIGN_REALDECL KMP_ALIGN16DECL
#	define KMP_ALIGN_NDECL KMP_ALIGN16DECL

#endif

#endif

#elif defined(KMP_ARM) && !defined(KMP_NO_ALIGN)

// use this in all your needs for alignment
#	define KMP_ALGN KMP_ALG_N8
#	define KMP_ALIGN_F32 KMP_ALIGN8
#	define KMP_ALIGN_F64 KMP_ALIGN8
#	define KMP_ALIGN_REAL KMP_ALIGN8
#	define KMP_ALIGN KMP_ALIGN8
#	define KMP_CLASS_ALIGN KMP_ALIGN8
#	define KMP_PREFIX_ALIGN KMP_ALIGN_PREFIX
#	define KMP_SUFFIX_ALIGN KMP_ALIGN_SUFFIX
#	define KMP_ALIGNMENT_DECL KMP_ALIGNMENTDECL
#	define KMP_ALIGN_DECL KMP_ALIGNDECL

// do not use this at all for portability issues
#	define KMP_ALIGN_F32DECL KMP_ALIGN8DECL
#	define KMP_ALIGN_F64DECL KMP_ALIGN8DECL
#	define KMP_ALIGN_REALDECL KMP_ALIGN8DECL
#	define KMP_ALIGN_NDECL KMP_ALIGN8DECL

#elif defined(KMP_NO_ALIGN)

// use this in all your needs for alignment
#	define KMP_ALGN 
#	define KMP_ALIGN_F32 KMP_ALIGN4
#	define KMP_ALIGN_F64 KMP_ALIGN4
#	define KMP_ALIGN_REAL KMP_ALIGN4
#	define KMP_ALIGN KMP_ALIGN4
#	define KMP_CLASS_ALIGN KMP_ALIGN4
#	define KMP_PREFIX_ALIGN KMP_ALIGN_PREFIX
#	define KMP_SUFFIX_ALIGN KMP_ALIGN_SUFFIX
#	define KMP_ALIGNMENT_DECL KMP_ALIGNMENTDECL
#	define KMP_ALIGN_DECL KMP_ALIGNDECL

// do not use this at all for portability issues
#	define KMP_ALIGN_F32DECL KMP_ALIGN4DECL
#	define KMP_ALIGN_F64DECL KMP_ALIGN4DECL
#	define KMP_ALIGN_REALDECL KMP_ALIGN4DECL
#	define KMP_ALIGN_NDECL KMP_ALIGN4DECL

#else

// use this in all your needs for alignment
#	define KMP_ALGN 
#	define KMP_ALIGN_F32 KMP_ALIGN4
#	define KMP_ALIGN_F64 KMP_ALIGN4
#	define KMP_ALIGN_REAL KMP_ALIGN4
#	define KMP_ALIGN KMP_ALIGN4
#	define KMP_CLASS_ALIGN KMP_ALIGN4
#	define KMP_PREFIX_ALIGN KMP_ALIGN_PREFIX
#	define KMP_SUFFIX_ALIGN KMP_ALIGN_SUFFIX
#	define KMP_ALIGNMENT_DECL KMP_ALIGNMENTDECL
#	define KMP_ALIGN_DECL KMP_ALIGNDECL

// do not use this at all for portability issues
#	define KMP_ALIGN_F32DECL KMP_ALIGN4DECL
#	define KMP_ALIGN_F64DECL KMP_ALIGN4DECL
#	define KMP_ALIGN_REALDECL KMP_ALIGN4DECL
#	define KMP_ALIGN_NDECL KMP_ALIGN4DECL

#endif

*/

// static assert
#define KMP_CT_ASSERT(ctaxp)	typedef char KMPCompileTimeAssert[(ctaxp) ? 1 : -1]


#if defined(KMP_VC)
#define KMP_OFFSET_OF(X, Y) offsetof(X, Y)
#else
#define KMP_OFFSET_OF(X, Y)
#endif

#if defined(KMP_X86) || defined(KMP_X64) || defined(KMP_XBOXONE)
#	if defined(KMP_VC) 
#		define KMP_BREAKPOINT(ID) __debugbreak();
#	endif
#elif defined(KMP_XBOX360)
#	if defined(KMP_VC) 
#		define KMP_BREAKPOINT(ID) __debugbreak();
#	endif
#elif defined(KMP_ARM)
#	if defined(KMP_VC) 
#		define KMP_BREAKPOINT(ID) __debugbreak();
#	endif
#endif

#define KMP_UNUSED(unp) (void)(unp);

// An expression that should expand to nothing in non KMP_DEBUG builds.  
// currently use this only for tagging the purpose of containers for memory use tracking.
#if defined(KMP_DEBUG)
#define KMP_DEBUG_EXP(dexp) (dexp)
#define KMP_DEBUG_EXP_C(dexp) dexp,
#else
#define KMP_DEBUG_EXP(dexp)
#define KMP_DEBUG_EXP_C(dexp)
#endif

#endif // KMP_BASEDEFS_H
